home *** CD-ROM | disk | FTP | other *** search
- /*
- * (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
- * use is allowed under the terms of the DICE-LICENSE FILE,
- * DICE-LICENSE.TXT.
- */
- /*
- ** $Id: vsuck.c,v 30.0 1994/06/10 18:09:35 dice Exp $
- **
- ** See what can be done with WIDEEXAMPLE
- **
- ** Start processing [$Marker] references
- **
- ** BUGS:
- ** Huge AslBase... line blows MAJOR_HEADING
- **
- ** strftime man page
- ** Notice <R> in tables
- ** Notice <197>
- **
- **
- ** !!!!!!!!!!!!!!!!!!!!!!!!!End-of-line blanks
- **
- ** Table mismatch in chap01.txt
- **
- **
- ** Flubs on:
- ** Spaces at end of line
- **
- ** Flubs on:
- ** @NAME = <TAB>KEYWORD<R>
- ** <TAB>SUBTITUTION
- **
- ** Flubs on:
- ** @OPTION = <TAB>-S0<R>
- ** <TAB>-S1
- **
- ** Does not handle <TAB> in @INPUT, @OUTPUT, etc.
- **
- ** atexit example has NULL in it.
- **
- ** FEATURES:
- ** The final line of paragrah terminated with <R> will have
- ** leading spaces stripped:
- ** #include <<stdio.h>><R>
- ** #include <<cats.h>>
- ** This will not be fixed; VReturn puts a final <R> on the
- ** last line.
- **
- ** TODO:
- ** Tab optimize
- ** Check exact length of MAJOR_HEADING wrap.
- **
- */
- #define D(x)
- #define D0(x)
- #define D1(x)
- #define D2(x)
- #define D3(x) x; // Warnings
- #define LINE_WIDTH 76 // So text won't wrap on 640 pixel wide screens
- #define MAX_PARAGRAPH 8000 // Yes... build that same limitation in.
-
- #define MIN_INDENT 4
- #define BODY_INDENT 8
- #define TABLE_INDENT 1
- #define OPTION_INDENT 12
- #define D_INDENT 28 // Text after options, results
- #define EXAMPLE_INDENT 4 // Extra bytes past normal indent
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define unless(x) if(!(x))
- #define CR 13
- #define LF 10
- #define FF 12
- #define TAB 9
-
-
- /*******************************************************************************
- ** Column Stuff
- */
- #define DC1 0x11 // Standin for ',' in tables 0x40.
- #define DC2 0x12 // Standin for <R> in tables 0x23.
- #define MAXCOLUMNS 10
-
- short hasheader; // Set if table has a header (thick line used)
-
- struct ColumnInfo { // Hold information about each of n columns
-
- // Prescan information
- short maxfirst; // Largest first word
- short maxword; // Largest word (make column no smaller!)
- short maxline; // Largest line (try to fit in this space)
- short tablelines; // Number of rows (redundant in each column)
- int total; // Total characters in this column (for ratio calc)
- short flags; //
-
- // Formatting information
- short col_start; // Start of actual text
- short col_width; // During format, location of vertical bar
- short col_temp;
- char *wrappointer; // Current index, or zero if column is done
- };
-
- /*******************************************************************************
- ** Globals
- */
- FILE *outfile; // FP for final output
-
- struct ColumnInfo ColInfo[MAXCOLUMNS]; // Array of ColumnInfo
-
- char allspaces[] =" ";
- char allhash[] ="################################################################################";
- char alldash[] ="--------------------------------------------------------------------------------";
- char outbuf[LINE_WIDTH*2]; // Leave room for CR,LF,NULL, slop
- char formatbuf[MAX_PARAGRAPH]; // Yes... build the same limitation in.
-
- #define INDENT_INVALID 0
- #define INDENT_OPTION 1 // *must* be followed by text
- #define INDENT_VFORMAT 2 // *may* be followed by text
- char indenttext[LINE_WIDTH*2]; // For text in the left margin
- char indenttextvalid=0; // -option This is an option
-
- int bodyindent =BODY_INDENT;
- int optionindent =OPTION_INDENT;
- int indent =BODY_INDENT;
-
- char *startinp; // Start of input
- register char *inp; // Walking input pointer
-
- int enum_val=1; // For @ENUM auto-counting
-
-
-
- /*******************************************************************************
- ** Prototypes
- */
- void ProcessFile();
- void putn(char *string,char terminator);
- void FormatParagraph(int slen,char *prestring1,char *prestring2);
- int CollectParagraph(void);
- int CollectTable(void);
- FilterSpaces(register char *leading);
- FilterCR(register char *leading);
-
-
- /******************************************************************************/
- main(int argc,char *argv[])
- {
- FILE *infile;
- long insize;
-
- if (argc != 3 || ( argc == 2 && *argv[1]=='?' ) ) {
- printf("VSuck <infile> <outfile>\n");
- printf("; Format a Ventura document as text. Like NROFF\n");
- exit(5);
- }
-
- unless( infile=fopen(argv[1],"r" ) ) {
- printf("Error: Can't read \"%s\"\n",argv[1]);
- exit(10);
- }
- unless( outfile=fopen(argv[2],"w" ) ) {
- printf("Error: Can't write to \"%s\"\n",argv[2]);
- fclose(infile);
- exit(10);
- }
-
- inp=0;
- fseek(infile,0,2);
- if( insize=ftell(infile) )
- {
- fseek(infile,0,0);
- if ( inp=malloc( insize+4 ) )
- {
- if ( insize==fread( inp,1,insize,infile ) )
- {
- inp[insize] =0; // Lots of space for sloppy code
- inp[insize+1]=0; // to read past without harm
- inp[insize+2]=0;
- inp[insize+3]=0;
- }
- else
- {
- printf("Error: Can't read \"%s\"\n",argv[1]);
- free( inp );
- inp=0;
- }
- }
- else
- {
- printf("Error: Out of memory (%ld bytes required)\n",insize+2);
- }
- }
-
- startinp=inp;
- if( inp ) {
- FilterCR(inp); // Delete all CR
- ProcessFile();
- free( startinp );
- }
-
- fclose( infile );
- fclose( outfile );
- printf("Exiting. Remember to tab & space optimize output!!!!\n");
- printf(" Remember to tab & space optimize output!!!! Have a nice day.\n");
- }
-
-
- /*******************************************************************************
- ** Misc utility functions
- */
- // Like puts, put terminates at given character
- void putn(char *string,char terminator)
- {
- char *temp;
-
- temp=strchr(string,terminator);
- if (temp)
- fwrite(string,temp-string+1,1,stdout);
- }
-
- // Like strnlen, but counts to given character
- int strlenc(s,c)
- const char *s;
- char c;
- {
- const char *b = s;
-
- while (*s != c)
- ++s;
-
- return(s - b);
- }
-
- // Given start and current, count newlines to come up with a line number
- // !!! TODO: Add cache
- int ErrorLine(char *start, char *current)
- {
- int linenum =1;
-
- for(;start < current; start++)
- if ( *start==LF )
- linenum++;
-
- return(linenum);
- }
-
- // Do in-place removal of spaces
- FilterSpaces(register char *leading)
- {
- register char *trailing=leading;
- register char c;
-
- while( c=*leading++ )
- {
- if (c != ' ')
- *trailing++=c;
- }
- *trailing=0;
- }
-
- // Do in-place removal of CR
- FilterCR(register char *leading)
- {
- register char *trailing=leading;
- register char c;
-
- while( c=*leading++ )
- {
- if (c != CR)
- *trailing++=c;
- }
- *trailing=0;
- trailing++;
- *trailing=0;
- trailing++;
- *trailing=0;
- trailing++;
- *trailing=0;
- trailing++;
- }
-
- /*******************************************************************************
- ** @ Functions
- */
-
- char *VFORMAT()
- {
- int len=0;
-
- len=CollectParagraph();
-
- unless(len && (len < LINE_WIDTH) ) {
- printf("Warning: @INPUTV/RESULTV no text/too long (%d)\n",ErrorLine(startinp,inp));
- return(0);
- }
- D(printf("@VFORMAT: inp=%lx,len=%d,indent=%d,string=%s\n",inp,len,indent,formatbuf));
-
- /* Treat VFORMAT like an option. New line if it won't fit properly.
- */
- if ( len+3 > (D_INDENT-indent-1))
- {
- memcpy(&outbuf[indent],&formatbuf[0],len+1); // Copy null
- fprintf(outfile,"%s\n",outbuf);
- }
- else{
- memcpy(&outbuf[indent],&formatbuf[0],len);
- strcpy(indenttext,outbuf); // Copy string + lots of spaces
- indenttextvalid=INDENT_VFORMAT;
- }
-
- return(0);
- }
-
-
- char *OPTION()
- {
- int len=0;
-
- len=CollectParagraph();
-
- unless(len && (len < LINE_WIDTH) ) {
- printf("Warning: @OPTION no text/too long (%d)\n",ErrorLine(startinp,inp));
- return(0);
- }
-
- D1(printf("@OPTION: inp=%lx,len=%d,indent=%d,string=%s\n",inp,len,indent,formatbuf));
-
- if ( formatbuf[0] == TAB )
- printf("Warning: TAB before OPTION text (%d)\n", ErrorLine(startinp,inp));
-
- /*
- ** If the option fits in the indent area, right justify it.
- ** else insert a line with just the option on it.
- **
- */
- if ( len+3 > indent)
- {
- memcpy(&outbuf[1] ,&formatbuf[0],len+1); // Copy null
- fprintf(outfile,"%s\n",outbuf);
- }
- else{
- memcpy(&outbuf[indent-len-2],&formatbuf[0],len);
- strcpy(indenttext,outbuf); // Copy string + lots of spaces
- indenttextvalid=INDENT_OPTION;
- }
-
- return(0);
- }
-
- char *MAJOR_HEADING()
- {
- int len;
- char *description=0; // Second part of new style MAJOR_HEADING lines
- // @MAJOR_HEADING = wc - Count words in file
-
- CollectParagraph();
-
- if ( description = strchr(formatbuf,'-') ) {
- if ( (description[-1] != ' ') || (description[1] != ' ') )
- printf("Warning: Non-standard dashed MAJOR_HEADING (%d)\n",ErrorLine(startinp,inp));
- description[-1] = 0;
- description += 2;
- }
-
- FilterSpaces(formatbuf);
- len=strlen(formatbuf);
-
- if ( 6+5+len+len+1 > LINE_WIDTH)
- {
- D3(printf("Warning: MAJOR_HEADING very long (%d bytes) (%d)\n",len , ErrorLine(startinp,inp)));
- fprintf(outfile,"dice/%s\n\n",formatbuf);
- }
- else {
- memcpy(outbuf ,"dice/",6);
- memcpy(outbuf+6,formatbuf,len);
- memcpy(outbuf+LINE_WIDTH-len-5+1,"dice/",5);
- memcpy(outbuf+LINE_WIDTH-len +1,formatbuf,len);
- outbuf[LINE_WIDTH+1]=0;
- fprintf(outfile,"%s\n\n",outbuf);
- }
-
- if ( description ) {
- fprintf(outfile,"",outfile);
- fwrite(allspaces,MIN_INDENT,1,outfile);
- fprintf(outfile,"FUNCTION\n");
- fwrite(allspaces,BODY_INDENT,1,outfile);
- fprintf(outfile,"%s\n\n",description);
- }
- }
-
- char *BEGINNER()
- {
- FormatParagraph(CollectParagraph(),":: ",":: ");
- }
-
- char *NOTE()
- {
- FormatParagraph(CollectParagraph(),"|| ","|| ");
- }
-
- char *WARNING()
- {
- FormatParagraph(CollectParagraph(),"## ","## ");
- }
-
- char *BULLET()
- {
- FormatParagraph(CollectParagraph(),"o "," ");
- }
-
- char *GENERIC()
- {
- FormatParagraph(CollectParagraph(),"","");
- }
-
- char *EXAMPLE()
- {
- // indent += EXAMPLE_INDENT;
- FormatParagraph(CollectParagraph(),"","");
- // indent -= EXAMPLE_INDENT;
- }
-
- char *ENUM()
- {
- char temp[16];
-
- sprintf(temp,"%d) ",enum_val);
- enum_val++;
- FormatParagraph(CollectParagraph(),temp," ");
- }
-
- char *CATEGORY()
- {
- fwrite(allspaces,MIN_INDENT,1,outfile);
- fprintf(outfile,"NAME\n");
- FormatParagraph(CollectParagraph(),"","");
- }
-
- char *NAME()
- {
- int len;
- char *temp;
-
- len=CollectParagraph();
- temp=formatbuf;
- if (len)
- if (formatbuf[0]==TAB) // TAB means right justify
- temp++;
- strcpy(&outbuf[MIN_INDENT],temp);
- fprintf(outfile,"%s\n",outbuf);
- }
-
- char *MINOR_HEADING()
- {
- int len;
- char *temp;
-
- len=CollectParagraph();
- temp=formatbuf;
-
- if (len)
- if (formatbuf[0]==TAB) { // TAB means right justify
- temp++;
- len--;
- printf("Warning: TAB in MINOR_HEADING (%d)\n", ErrorLine(startinp,inp));
- }
- if (len) {
- strcpy(&outbuf[MIN_INDENT],temp);
- fprintf(outfile,"%s\n",outbuf);
- memcpy(&outbuf[MIN_INDENT],alldash,len);
- outbuf[MIN_INDENT+len]=0;
- fprintf(outfile,"%s\n",outbuf);
- }
- }
-
- char *Z_TBL_BEG()
- {
-
- // Skip @Z_TBL_BEG. Turns out, we don't use any information from it!
- while( *inp && !(inp[0]==LF && inp[1]==LF) )
- inp++;
-
- // Strip formatting
- CollectTable();
- D1(printf("@TABLE: inp=%lx,string=\n%s\n",inp,formatbuf));
-
- // Collect statistics, then Write to output
- WriteTable(PrescanTable(formatbuf),formatbuf);
- }
-
-
- /*
- ** Figure out how to format the table
- */
- #define MAGIC_SMALLCOLUMN 11 // Treat small first columns preferentially
-
- int ThinkDeeply(int columns)
- {
- int leftmargin;
- int i,j,whatif,whatif2;
- short columnspace; // Space available to assign widths
-
- columnspace = LINE_WIDTH-TABLE_INDENT-((columns-1)*3);
- D1(printf("ThinkDeeply: Assignable columns = %d\n",columnspace));
-
- /*
- ** Determine if table is impossible, and clear out col_start/col_width
- */
- whatif=0;
- for ( i=0; i < columns; i++) {
- whatif += (ColInfo[i].maxword);
- ColInfo[i].col_start = 0;
- ColInfo[i].col_width = 0;
- ColInfo[i].col_temp = 0;
- ColInfo[i].wrappointer = 0;
- }
- if (whatif > columnspace ) {
- printf("Error: Impossible table; words too large (%d)\n",ErrorLine(startinp,inp));
- return(0);
- }
-
- /*
- ** Now try to fit all text on a single line
- */
- whatif=0;
- for ( i=0; i < columns; i++)
- whatif += (ColInfo[i].maxline);
- D1(printf("Total maximum length (whatif)=%d\n",whatif));
-
- /*
- ** Ideal Situation. Everything fits on one line. Center the column
- */
- if (whatif < columnspace ) {
- leftmargin = ((columnspace-whatif) / 2) + TABLE_INDENT;
- j = leftmargin;
- for ( i=0; i< columns; i++) {
- ColInfo[i].col_start = j;
- ColInfo[i].col_width = ColInfo[i].maxline;
- j = j + 3 + ColInfo[i].maxline;
- }
- D1(printf("ThinkDeeply chooses: Single line\n"));
- return(leftmargin);
- }
-
- /*
- ** Next, fit small first column with single large second column
- */
- if ( columns == 2 && ColInfo[0].maxline < MAGIC_SMALLCOLUMN ) {
- ColInfo[0].col_start = TABLE_INDENT;
- ColInfo[0].col_width = ColInfo[0].maxline;
- ColInfo[1].col_start = ColInfo[0].maxline+TABLE_INDENT+3;
- ColInfo[1].col_width = LINE_WIDTH-TABLE_INDENT-3-ColInfo[0].maxline;
- D1(printf("ThinkDeeply chooses: Small first column\n"));
- return(TABLE_INDENT);
- }
-
- /*
- ** No tricks worked :-(. Assign widths based on weight of text. The
- ** more text in a column, the wider. No column may be smaller than
- ** the largest word.
- **
- */
- // First, add up total of all text.
- whatif = 0;
- for ( i=0; i < columns; i++) {
- whatif += ColInfo[i].total;
- }
- D1(printf("ThinkDeeply brute force: %d total characters\n",whatif));
-
- // Second, calculate ratios. More text means larger column.
- whatif *= 1000; // Total chars
- whatif2 = whatif / columnspace; // Space avail
-
- // Third. Assign columns based on ratios.
- for ( i=0; i < columns; i++) {
- j = ColInfo[i].total;
- D1(printf("Aproximate column width = %d\n",(j * 1000) / whatif2));
- ColInfo[i].col_temp = ((j * 1000) / whatif2);
- ColInfo[i].col_width= 0;
- }
-
- // Fourth. Evaluate results against rules and assign hard values
- for ( i=0; i < columns; i++) {
- j = ColInfo[i].col_temp;
-
- // If assigned column was too small, hard assign minimum width
- if ( j < ColInfo[i].maxword )
- ColInfo[i].col_width=ColInfo[i].maxword;
-
- // If assigned column larger than longest line, trim to minimum
- if ( j > ColInfo[i].maxline )
- ColInfo[i].col_width=ColInfo[i].maxline;
-
- D1(printf("Hard-set column width = %d\n",ColInfo[i].col_width));
- }
-
- // Fifth, add up text in columns which don't yet have a fixed size,
- // and number of already-assigned columns.
- whatif = 0;
- whatif2 = 0;
- for ( i=0; i < columns; i++ ) {
- if ( ColInfo[i].col_width )
- whatif2 += ColInfo[i].col_width;
- else
- whatif += ColInfo[i].total;
- }
- D1(printf("After fixed assignments: %d total, %d preassigned\n",whatif,whatif2));
-
-
- // Second, calculate ratios. More text means larger column.
- whatif *= 1000; // Total chars in unassigned columns
- whatif2 = whatif / (columnspace-whatif2); // Space avail
-
- // Third. Assign columns based on ratios.
- for ( i=0; i < columns; i++) {
- j = ColInfo[i].total;
- if ( 0==ColInfo[i].col_width) {
- D1(printf("Col %d new aprox. width = %d\n",i,(j * 1000) / whatif2));
- ColInfo[i].col_width = ((j * 1000) / whatif2);
- }
- }
-
- //
- // !!! :TODO: Readjust plus or minus to fix any rounding errors
- // in total assignment.
- //
- j = TABLE_INDENT;
- for ( i=0; i< columns; i++) {
- ColInfo[i].col_start = j;
- j = j + 3 + ColInfo[i].col_width;
- }
- D1(printf("ThinkDeeply chooses: Complex fit\n"));
- return(TABLE_INDENT);
- }
-
-
-
-
- /*
- ** Dump a ColumnInfo structure.
- */
- PrintCI(int x)
- {
- printf("## %02d First=%02d Word=%02d Line=%04d Total=%04d Lines=%02d/Start=%02d Width=%02d Wrap=%lx\n",
- x,ColInfo[x].maxfirst,ColInfo[x].maxword,ColInfo[x].maxline,ColInfo[x].total,
- ColInfo[x].tablelines,ColInfo[x].col_start,ColInfo[x].col_width,
- ColInfo[x].wrappointer);
- }
-
- /*
- ** Write table. Given:
- ** Columns
- ** Information for each column
- ** Formatting-stripped, comma separated entries
- */
- WriteTable(int columns,char *table)
- {
- short flag;
- short cl_width,cl_start;
- int i,j;
-
- char * start;
- char * current;
- char * lastword; // End of last word encountered (for word wrap).
- char * temp;
- char rulechar='='; // Character used for thick horizontal ruling lines
-
- short leftmargin;
-
-
- leftmargin = ThinkDeeply(columns);
-
-
- D1(for ( i=0; i< columns; i++))
- D1(PrintCI(i));
- D1(printf("^^ Final statistics for table ending at line %d ^^\n",ErrorLine(startinp,inp)));
-
- unless( leftmargin ) {
- printf("Error: ThinkDeeply() could not resolve table (%d)\n",ErrorLine(startinp,inp));
- return(0);
- }
-
- while( *table )
- {
- // Position wrappointer at start of each column (just past ',')
- temp = table;
- for ( i=0; i< columns; i++) {
- ColInfo[i].wrappointer = temp;
- while( *temp && (*temp != DC1) && (*temp != LF) )
- temp++;
- temp++;
- }
- temp--;
- if ( *temp != LF )
- printf("Warning: column count mismatch!\n");
-
- #ifdef NDEF
- for ( i=0; i< columns; i++) {
- printf("Col %d=%lx,%c%c\t",i,ColInfo[i].wrappointer,*(ColInfo[i].wrappointer),*(ColInfo[i].wrappointer+1));
- }
- printf("\n");
- #endif
-
- flag =1; // Zero when all columns have flowed all text
- while( flag ) {
- for(i=0; i<LINE_WIDTH+15; i++)
- outbuf[i]=' ';
-
- for ( i=0; i< columns; i++) {
- lastword = NULL;
- cl_width=ColInfo[i].col_width;
- cl_start=ColInfo[i].col_start;
- if ( i != columns-1 ) // Except for last column
- outbuf[cl_width+cl_start+1]=':';
- if ( start=current=ColInfo[i].wrappointer ) {
- while( *current==' ' || *current=='\t' || *current==DC2 )
- start++, current++;
- int noDC2seen = 1;
- while( *current ) {
- if ( *current == ' ' || *current == '\t' || *current == DC1 || *current == LF || *current == DC2 )
- if ( current-start <= cl_width )
- if ( noDC2seen ) {
- lastword = current; // Last full word
- if( *current == DC2 )
- noDC2seen = 0;
- }
- if ( *current == DC1 || *current == LF ) {
- if (lastword && (lastword-start)) {
- memcpy(&outbuf[cl_start],start,lastword-start);
- }
- if ( lastword == current)
- ColInfo[i].wrappointer = NULL;
- else
- ColInfo[i].wrappointer = lastword;
- break;
- }
- current++;
- }
- }
- }
-
- outbuf[LINE_WIDTH+14]=0;
- fprintf(outfile,"%s\n",outbuf);
-
- flag =0;
- for ( i=0; i< columns; i++)
- if (ColInfo[i].wrappointer)
- flag=1;
- }
-
- /*
- ** Print middle ruling lines
- */
- if( !hasheader )
- rulechar='-'; // Switch immediatly to thin lines
-
- for(i=0; i<LINE_WIDTH; i++)
- outbuf[i]=' ';
- for ( i=0; i< columns; i++) {
- cl_width=ColInfo[i].col_width;
- cl_start=ColInfo[i].col_start;
-
- for( j=cl_start; j < cl_start+cl_width+1; j++)
- outbuf[j]=rulechar;
- outbuf[j]=0;
- if ( i != columns-1 )
- outbuf[j]='+', outbuf[j+1]=rulechar;
- }
- fprintf(outfile,"%s\n",outbuf);
- rulechar='-'; // Switch immediatly to thin lines
-
- while( *table && *table != LF) // Skip to next line
- table++;
- table++;
- }
- fprintf(outfile,"\n");
- }
-
- /*
- ** Scan table, counting colums and gathering statistics. Assumes
- ** all formatting codes have been stripped.
- **
- ** Count number of columns. For each column, record:
- ** Max first word.
- ** Max word.
- ** Max line.
- ** Total characters.
- */
- int PrescanTable(char *table)
- {
- short cnt_chars=0; // Running total of characters on line
- short cnt_wordchars=0; // Running count of current word
-
- short cnt_columns=0; // Count of columns on current line
- short tot_columns=0; // Check point. Do all lines have same # columns?
-
- short cnt_firstword=0; // Size of first word, copied to ColInfo
- short cnt_maxword=0; // Size of max word, copid to ColInfo
- int i;
-
- for ( i=0; i < MAXCOLUMNS; i++) {
- clrmem( ColInfo, sizeof(ColInfo) );
- }
-
- while( *table )
- {
- switch ( *table )
- {
- case ' ': // (Note dupe in next case)
- case DC2:
- if( !cnt_firstword )
- cnt_firstword = cnt_chars; // Length of first word
- if( cnt_wordchars > cnt_maxword )
- cnt_maxword = cnt_wordchars; // Length of largest word
-
- cnt_chars++;
- cnt_wordchars=0;
- break;
- case DC1:
- case LF:
- if( !cnt_firstword )
- cnt_firstword = cnt_chars; // Length of first word
- if( cnt_wordchars > cnt_maxword )
- cnt_maxword = cnt_wordchars; // Length of largest word
-
- if (ColInfo[cnt_columns].maxfirst < cnt_firstword)
- ColInfo[cnt_columns].maxfirst = cnt_firstword;
- if (ColInfo[cnt_columns].maxline < cnt_chars)
- ColInfo[cnt_columns].maxline = cnt_chars;
- if (ColInfo[cnt_columns].maxword < cnt_maxword)
- ColInfo[cnt_columns].maxword = cnt_maxword;
- ColInfo[cnt_columns].total += cnt_chars;
- ColInfo[cnt_columns].tablelines += 1;
-
- cnt_columns++; // Move to next column
- if ( *table == LF)
- {
- if ( tot_columns )
- if ( cnt_columns != tot_columns)
- printf("Error: Column count mismatch %d != %d (%d)\n",
- tot_columns, cnt_columns, ErrorLine(startinp,inp));
- tot_columns =cnt_columns;
- if ( tot_columns > MAXCOLUMNS-1 )
- printf("Error: Too many columns! (%d)\n", ErrorLine(startinp,inp));
- cnt_columns =0;
- }
-
- cnt_firstword =0;
- cnt_maxword =0;
- cnt_chars =0;
- cnt_wordchars =0;
- break;
- default:
- cnt_chars++;
- cnt_wordchars++;
- }
- table++;
- }
-
- return( tot_columns );
- }
-
- /*
- ** Strip off all table junk to product comma separated list.
- ** Record if a table heading (@Z_TBL_HEAD) was seen.
- */
- int CollectTable()
- {
- int i=0;
-
- hasheader=0;
-
- while( *inp )
- {
-
- while (*inp == LF)
- inp++;
-
- if ( *inp == '@' )
- {
- if ( 0 == strncmp(inp, "@Z_TBL_END", 10) )
- {
- D1(printf("TBL_END\n"));
- while( *inp && !(inp[0]==LF && inp[1]==LF) )
- inp++;
- break;
- }
- if ( 0 == strncmp(inp, "@Z_TBL_HEAD", 10) )
- {
- D1(printf("TBL_TBL_HEAD\n"));
- hasheader=1;
- }
- while (*inp && *inp != LF) // Skip @ command
- inp++;
- } else {
- while( *inp )
- {
- if ( i > (MAX_PARAGRAPH-100) ) {
- printf("Error: Paragraph too large!\n");
- break;
- }
-
- /* Escape ++, -- and ,,. What a spitwad.
- ** Does not handle joined columns "+," and "^,"
- */
- if ( inp[0] == LF && inp[1] == LF ) {
- formatbuf[i++]= LF, inp+=2;
- break;
- }
- else if ( inp[0] == '+' && inp[1] == '+' )
- formatbuf[i++] ='+', inp++;
- else if ( inp[0] == '^' && inp[1] == '^' )
- formatbuf[i++]= '^', inp++;
- else if ( inp[0] == '<' && inp[1] == '<' )
- formatbuf[i++]= '<', inp++;
- else if ( inp[0] == '>' && inp[1] == '>' )
- formatbuf[i++]= '>', inp++;
- else if ( inp[0] == '<' && inp[1] == 'R' && inp[2] == '>' )
- formatbuf[i++]= DC2, inp+=3;
- else if ( inp[0] == ',' && inp[1] == ',' )
- formatbuf[i++]= ',', inp++;
- else if ( inp[0] == ',' && inp[1] == ' ' )
- formatbuf[i++]= DC1, inp++;
- else if ( inp[0] == ',' )
- formatbuf[i++]= DC1;
- else if ( inp[0] == LF )
- formatbuf[i++]= ' ';
- else if ( inp[0] == '<' )
- {
- short nest=1;
- while( *inp++ && nest )
- {
- switch( *inp )
- {
- case '>':
- nest--;
- break;
- case '<':
- nest++;
- default:
- }
- }
- inp--;
- }
- else
- formatbuf[i++]=*inp;
- inp++;
- }
- }
- }
- formatbuf[i]=0;
- formatbuf[i+1]=0;
- formatbuf[i+2]=0;
- formatbuf[i+3]=0;
- return(i);
- }
-
- int CollectParagraph()
- {
- int i=0;
-
- while( *inp )
- {
- if ( (*inp==LF) && (*(inp+1)==LF) ) // Two LF's signal end of para
- break;
-
- if ( *inp==CR ) {
- printf("Error: File must not contain CR's\n");
- break;
- }
-
- if ( i > (MAX_PARAGRAPH-100) ) {
- printf("Error: Paragraph too large!\n");
- break;
- }
-
- // Escape double <<brackets>>. Skip single <brackets>
- //
- if ( inp[0] == '<' && inp[1] == '<' )
- formatbuf[i++]='<',inp += 2;
- else if ( inp[0] == '>' && inp[1] == '>' )
- formatbuf[i++]='>',inp += 2;
- else if ( inp[0] == '<' ) {
- if ( inp[1]=='R' && inp[2]=='>' ) // Convert <R> to LF
- {
- formatbuf[i++]=LF;
- if ( inp[3] == '\n' )
- inp++;
- inp += 3;
- }
- else if ( inp[1]=='N' && inp[2]=='>' ) // Convert <N> to ` `
- {
- formatbuf[i++]=' ';
- if ( inp[3] == '\n' )
- inp++;
- inp += 3;
- }
- else if ( inp[1]=='$' && inp[2]=='R' )
- {
- while( *inp && *inp++ != ']' )
- ;
- if( *inp == '>')
- printf("Warning: No chapter number in Cross-Ref (%d)\n",ErrorLine(startinp,inp));
- while( *inp && (*inp != '>') ) {
- formatbuf[i++] = *inp;
- inp++;
- }
- inp++;
- }
- else {
- short nest=1;
- inp++;
- while( *inp && nest )
- {
- switch( *inp )
- {
- case '>':
- nest--;
- break;
- case '<':
- nest++;
- default:
- }
- inp++;
- }
- }
- }
- /*
- ** Ventura seems to put a space at the end of lines, but also
- ** accept files without the space. As a guess, I force a single
- ** space to the end of the line if none, else accept any number
- ** of spaces found there.
- */
- else if ( *inp == LF ) {
- if(!( formatbuf[i-1]==' ' ))
- formatbuf[i++]=' ';
- inp++;
- }
- else
- formatbuf[i++]=*inp,inp++;
- }
- formatbuf[i]=0;
- formatbuf[i+1]=0;
- formatbuf[i+2]=0;
- formatbuf[i+3]=0;
-
- return(i);
- }
-
- void FormatParagraph(int slen,char *prestring1,char *prestring2)
- {
- int pass=0;
- int pos=0;
- int scan=0;
- int perline= LINE_WIDTH + 1 - strlen(prestring1) - indent;
- int i;
-
- D2(printf("FormatParagraph. Slen=%d, pre1=%s,pre2=%s\n", slen, prestring1,prestring2));
- D2(printf("%s", formatbuf));
-
- // Process normal text paragraph. Wrap words, nuke spaces at start
- // of line, etc. Handle <R>, grumble.
- while ( pos < slen )
- {
-
- // If there is a newline within the current line range, pump out
- // that string. Else set scan to just past end of line (or EOF)
- // and work backwards to word-wrap.
- scan=0;
- for (i=0; i < perline; i++)
- {
- if ( !formatbuf[pos+i] )
- break;
- if ( formatbuf[pos+i] == '\n' )
- {
- scan = pos+i+1; // Include linefeed
- D(printf("Newline found at %d\n",i));
- break;
- }
- }
-
- if( !scan )
- {
- // Skip leading spaces
- while ( formatbuf[pos]==' ' || formatbuf[pos]=='\t' )
- pos++;
- if ( pos >= slen )
- break;
-
- scan = pos + perline; // Just past end of line
-
- if ( scan > slen)
- scan = slen; // Set to EOF
-
- // Scan backwards for NULL, LF, space separator or start of line
- while( scan > pos && formatbuf[scan] && formatbuf[scan] != ' ' && formatbuf[scan] != '\t' )
- scan--;
-
- D(printf("Word-wrapped to %d bytes\n",scan-pos));
-
- if (pos == scan)
- printf("ERROR: Huge word (near line %d)\n",ErrorLine(startinp,inp));
- }
-
- if ( indenttextvalid )
- fwrite(indenttext,indent,1,outfile), indenttextvalid=0;
- else
- fwrite(allspaces,indent,1,outfile);
-
- if ( pass )
- fprintf(outfile,prestring2);
- else
- fprintf(outfile,prestring1);
-
- fwrite(&formatbuf[pos],scan-pos,1,outfile);
- if ( formatbuf[scan-1] != '\n' )
- fprintf(outfile,"\n");
-
- pos = scan;
- pass++;
- }
- fprintf(outfile,"\n");
- }
-
-
- /*******************************************************************************
- ** @ Function tables & flags
- */
- #define ATSKIP 4 // Longs per atstuff entry
-
- #define AF_OPT 0x0001 // Option indenting
- #define AF_BODY 0x0002 // Body indenting
- #define AF_NOFLUSH 0x0004 // Disable flush before next @COMMAND
- #define AF_ENUM 0x0008 // Don't reset enum_val
- #define AF_INDENTOK 0x0010 // For @ command, indent text is ok.
-
- // SNAME is like NAME, but should have no space above. We can't do
- // this, however :-).
- void *(*atstuff[])()={
- "@NAME", NAME, AF_BODY, BODY_INDENT,
- "@SNAME", NAME, AF_BODY, BODY_INDENT,
- "@OPTION", OPTION, AF_OPT, OPTION_INDENT,
- "@INPUTV", VFORMAT, AF_BODY, BODY_INDENT,
- "@RESULTV", VFORMAT, AF_BODY, BODY_INDENT,
- "@INPUTD", GENERIC, AF_INDENTOK, D_INDENT,
- "@RESULTD", GENERIC, AF_INDENTOK, D_INDENT,
- "@MINOR HEADING", MINOR_HEADING, AF_BODY, BODY_INDENT,
- "@MAJOR HEADING", MAJOR_HEADING, AF_BODY, BODY_INDENT,
- "@CATEGORY", CATEGORY, AF_BODY, BODY_INDENT,
- "@BULLET", BULLET, AF_BODY, BODY_INDENT,
- "@BEGINNER", BEGINNER, AF_BODY, 0,
- "@NOTE", NOTE, AF_BODY, 0,
- "@WARNING", WARNING, AF_BODY, 0,
- "@VERBATIM", GENERIC, AF_BODY, 0,
- "@FUNCTION", GENERIC, AF_BODY, BODY_INDENT,
- "@LIBRARY", GENERIC, AF_BODY, BODY_INDENT,
- "@SYNTAX", GENERIC, AF_BODY, BODY_INDENT,
- "@INPUTS", GENERIC, AF_BODY, BODY_INDENT,
- "@RESULTS", GENERIC, AF_BODY, BODY_INDENT,
- "@DESCRIPTION", GENERIC, AF_BODY, BODY_INDENT,
- "@AME_BODY", GENERIC, AF_BODY, BODY_INDENT,
- "@EXAMPLE_LIB", EXAMPLE, AF_OPT, 0,
- "@EXAMPLE", EXAMPLE, AF_OPT, 0,
- "@WIDEEXAMPLE", EXAMPLE, AF_OPT, 0,
- "@SEE ALSO", GENERIC, AF_BODY, BODY_INDENT,
- "@ENUM", ENUM, AF_ENUM, BODY_INDENT,
- "@Z_TBL_BEG", Z_TBL_BEG, AF_BODY, 0,
- "@Body Text", GENERIC, AF_BODY, BODY_INDENT,
- 0, 0, 0, BODY_INDENT,
- };
-
- #ifdef NOTDEF
- struct STRINGS partypes[] = {
- { 0, "CHAPTER HEAD", NULL },
- { 0, "INPUTV", NULL },
- { 0, "INPUTD", NULL },
- { 0, "Z_TBL_BEG", NULL },
- { 0, "Z_TBL_BODY", NULL },
- { 0, "Z_TBL_HEAD", NULL },
- { 0, "Z_TBL_END", NULL },
- { 0, "STEP2", NULL },
- { 0, "PARAFILTER ON", NULL },
- { 0, "ERRMESS", NULL },
- { 0, "INDEN1", NULL },
- { 0, "INDEN2", NULL },
- { 0, "INDEN2M", NULL },
- { 0, "INDEN2B", NULL },
- { 0, "INDENT", NULL },
- { 0, "INDEN2MID", NULL },
- { 0, "INDEN1MID", NULL },
- { 0, "INDEN1BOT", NULL },
- { 0, "INDEN2BOT", NULL },
- { 0, "LISTCAP", NULL },
- { 0, "LISTBODY", NULL },
- { 0, "CAPTION", NULL },
- { 0, "DEFINES", NULL },
- { 0, "TBL TITLE", NULL },
- };
- #endif
-
- /*******************************************************************************
- ** Processfile. Until reaching a null, scan the input file for
- ** @XXX keywords. Executue @ function, or print warning and keep
- ** scanning.
- */
- void ProcessFile()
- {
- int j;
- int atindex;
- // char *temp; DICE BUG
-
- D(printf("ProccessFile: outfile=%lx, inp=%lx\n",outfile,inp));
-
- while( *inp )
- {
- if (*inp == LF)
- *inp++;
- else if (*inp == CR)
- {
- printf("Error: File must not contain CR's\n");
- break;
- }
- else if (*inp == '@')
- {
- /*
- ** Find matching @ command
- */
- for( atindex=0; atstuff[atindex]; atindex += ATSKIP)
- {
- if( !strncmp(atstuff[atindex], inp, strlen(atstuff[atindex])) )
- break;
- }
-
- /*
- ** Execute @ command, if any. Else flush any pending line.
- */
- if( !atstuff[atindex] )
- {
- printf("Warning: Unmatched tag: "),putn(inp,'='),printf("\n");
-
- // Skip to next signifcant thing
- inp++;
- while( *inp && !(*inp=='@') && !(inp[0]==LF && inp[1]==LF) )
- inp++;
- }
- else{
- D2( printf("Matched tag: %s\n",atstuff[atindex]) );
-
- while( *inp && !(*inp=='=') ) // Skip to '='
- inp++;
- unless( inp[1]==' ' && inp[2])
- {
- D3(printf("Warning: nothing after @ tag (%d)\n",ErrorLine(startinp,inp)));
- while( *inp && !(*inp=='@') && !(inp[0]==LF && inp[1]==LF) )
- inp++;
- }
- else {
- inp += 2;
-
- unless( ((int)atstuff[atindex+2]) & AF_ENUM )
- enum_val = 1; // Reset ENUM count
-
- if( atstuff[atindex+3] )
- indent = (int)atstuff[atindex+3];
-
- unless( ((int)atstuff[atindex+2]) & AF_INDENTOK ) {
- if( indenttextvalid == INDENT_OPTION ) {
- printf("Warning: Left margin text lost (%d)\n", ErrorLine(startinp,inp));
- printf("Warning: Text lost was \"%s\"\n", indenttext);
- }
- else if( indenttextvalid == INDENT_VFORMAT )
- fprintf(outfile,"%s\n\n",indenttext);
-
- for( j=0; j<LINE_WIDTH+2; j++)
- outbuf[j]=' ';
- outbuf[j+1]=0;
-
- indenttextvalid =0;
- }
-
- (*atstuff[atindex+1])(inp);
- }
- }
- }
- else{
- enum_val = 1; // Body text resets ENUM to base
-
- FormatParagraph(CollectParagraph(),"","");
- }
- }
- D(printf("End ProccessFile: outfile=%lx, inp=%lx\n",outfile,inp));
- }
-